#ifndef VETOR_H_
#define VETOR_H_
#include <stdexcept>
#include <cstdlib>
#include <iostream>

using namespace std;

class ExcecaoVetor : public runtime_error
{
public:
	ExcecaoVetor(char *tipo_e) : runtime_error(tipo_e) { } 
};

template < class TIPO > 
class Vetor
{
private:
	TIPO *Dados; 	// Ponteiro para meu vetor tradicional alocado dinamicamente
	int TamMaximo; 	// Numero de itens alocado em memoria
	int Iterador; 	// Armazena a posição de inserção do proximo elemento
// Metodo Utilitário
	void RealocaMemoria(int num_elementos_adicional);
public:
	Vetor(int tam_inicial = 0);
	Vetor(const Vetor &copia);
	virtual ~Vetor();
//Operações do Vetor
	void Insere(TIPO elemento); // Lança excecao para vetor cheio
	TIPO GetValor(int posicao); // Lança excecao para posicao invalida!!
	int GetNumValores();
	int GetCapacidade();
	bool Vazio();
	bool Cheio();
	double GetMedia() const;
// Operadores Logicos!
	bool operator==( Vetor &v_dir );
	bool operator!=( Vetor &v_dir );
	Vetor &operator=(Vetor &v_dir);
//Operadores de Acesso
	TIPO operator[](int pos);
	friend ostream &operator<<(ostream &out, Vetor &v_dir);
	friend istream &operator>>(istream &in, Vetor &v_dir);
	//friend void operator=(Vetor &dest, Vetor &ori);
};

template <class TIPO> 
Vetor<TIPO>::Vetor(int tam_inicial)
{
	if(tam_inicial <= 0)
	{
		tam_inicial = 100;
	}
	Dados = new TIPO[tam_inicial];
	TamMaximo = tam_inicial;
	Iterador = 0;
}

template <class TIPO> 
Vetor<TIPO>::Vetor(const Vetor &copia)
{
	if(copia.TamMaximo > 0)
	{
		Dados = new TIPO[ copia.TamMaximo ];
		for(int i = 0; i < copia.Iterador; i++)
		{
			Dados[i] = copia.Dados[i];			
		}
	}
	else
	{
		Dados = NULL;
	}
	TamMaximo = copia.TamMaximo;
	Iterador = copia.Iterador;
}

template <class TIPO> 
Vetor<TIPO>::~Vetor()
{
	delete [] Dados;
}

template <class TIPO> 
void Vetor<TIPO>::Insere(TIPO elemento)
{
	if( Cheio() )
	{
		throw ExcecaoVetor("Vetor Cheio!");
	}
	Dados[Iterador] = elemento;
	Iterador++;	
}

template <class TIPO> 
TIPO Vetor<TIPO>::GetValor(int posicao)
{
	if(posicao >= Iterador)
	{
		throw ExcecaoVetor("Posicao Invalida!!");
	}
	return  Dados[posicao];	
}

template <class TIPO> 
int Vetor<TIPO>::GetNumValores()
{
	return Iterador;
}

template <class TIPO> 
int Vetor<TIPO>::GetCapacidade()
{
	return TamMaximo;
}

template <class TIPO> 
bool Vetor<TIPO>::Vazio()
{
	return (Iterador == 0);	
}
template <class TIPO> 
bool Vetor<TIPO>::Cheio()
{ 
	return (TamMaximo == Iterador);
}

template <class TIPO> 
void Vetor<TIPO>::RealocaMemoria(int num_elementos_adicional)
{
	int novo_tam = TamMaximo + num_elementos_adicional;
	int *tmp = new TIPO[novo_tam];
	for(int i = 0; i < Iterador; i++)
	{
		tmp[i] = Dados[i];
	}
	TIPO *paux = Dados; // variavel auxiliar
	Dados = tmp;
	delete [] paux;
	TamMaximo = novo_tam;
}
/**
 * Mesmo tamanho e todos os valores iguais aos valores de v_dir!!
 */
template <class TIPO> 
bool Vetor<TIPO>::operator==( Vetor &v_dir )
{
	if(Iterador != v_dir.Iterador)
	{
		return false;
	}
	for(int i = 0; i < Iterador; i++)
	{
		if(Dados[i] != v_dir.Dados[i])
		{
			return false;
		}	
	}
	return true;
}

template <class TIPO> 
bool Vetor<TIPO>::operator!=( Vetor &v_dir )
{
	return ( !(*this == v_dir) );
}

template <class TIPO> 
Vetor<TIPO> &Vetor<TIPO>::operator=(Vetor &v_dir)
{
	if(Dados != NULL)
	{
		delete [] Dados;
	}
	TamMaximo = v_dir.TamMaximo;
	Iterador = v_dir.Iterador;
	Dados = new TIPO[TamMaximo];
	for(int i = 0; i < Iterador; i++)
		Dados[i] = v_dir.Dados[i];
	return *this;	
}

template <class TIPO> 
TIPO Vetor<TIPO>::operator[](int pos)
{
	return GetValor(pos);	
}

#endif /*VETOR_H_*/
